Chapter 01

머신러닝이란 무엇인가?

1.1 머신러닝의 정의

머신러닝(Machine Learning)은 컴퓨터가 명시적으로 프로그래밍되지 않아도 데이터에서 패턴을 학습하여 예측이나 결정을 내리는 인공지능의 한 분야입니다. 전통적인 프로그래밍에서는 사람이 규칙을 코드로 작성하지만, 머신러닝에서는 데이터와 결과를 주면 컴퓨터가 스스로 규칙을 발견합니다.

예를 들어, "스팸 메일을 걸러라"라는 문제에서 전통 프로그래밍은 "특정 단어가 포함되면 스팸"이라는 규칙을 사람이 직접 만들지만, 머신러닝은 수천 개의 스팸/정상 메일 데이터를 보고 컴퓨터가 스스로 패턴을 찾아냅니다.

1.2 머신러닝의 세 가지 유형

유형영문설명대표 알고리즘
지도 학습Supervised Learning입력(X)과 정답(y)이 모두 주어진 상태에서 학습회귀, 분류, SVM, 랜덤 포레스트
비지도 학습Unsupervised Learning정답 없이 데이터의 구조·패턴만으로 학습K-Means, PCA, DBSCAN
강화 학습Reinforcement Learning보상/벌칙 피드백을 통해 최적 전략 학습Q-Learning, DQN, PPO

Scikit-Learn은 이 중에서 지도 학습비지도 학습에 특화된 라이브러리입니다. 강화 학습은 별도의 라이브러리(OpenAI Gym, Stable Baselines 등)를 사용합니다.

1.3 지도 학습 : 회귀 vs 분류

지도 학습은 예측하려는 대상(타겟, y)의 성격에 따라 두 가지로 나뉩니다.

구분타겟 변수예시
회귀 (Regression)연속적인 숫자집값 예측, 주가 예측, 기온 예측
분류 (Classification)이산적인 범주/라벨스팸 여부, 품종 분류, 질병 진단

1.4 머신러닝 작업 흐름

어떤 머신러닝 프로젝트든 아래의 기본 흐름을 따릅니다. 이 튜토리얼 전체가 이 흐름을 따라가며 각 단계를 상세히 다룹니다.

머신러닝 기본 워크플로우
① 문제 정의 → ② 데이터 수집 → ③ 데이터 전처리 → ④ 탐색적 데이터 분석(EDA) → ⑤ 모델 선택 → ⑥ 모델 학습(fit) → ⑦ 모델 평가 → ⑧ 하이퍼파라미터 튜닝 → ⑨ 최종 예측 · 배포

1.5 핵심 용어 정리

용어영문설명
특성 (피처)Feature모델에 입력되는 개별 변수 (X의 각 열)
타겟 (레이블)Target / Label예측하고자 하는 정답 (y)
샘플Sample하나의 데이터 행 (관측치)
학습 (훈련)Training / Fit데이터를 이용해 모델의 파라미터를 조정하는 과정
예측 (추론)Prediction / Inference학습된 모델로 새 데이터의 결과를 추정
과적합Overfitting훈련 데이터에 지나치게 맞춰져 새 데이터에 성능이 떨어지는 현상
과소적합Underfitting모델이 데이터의 패턴을 충분히 학습하지 못한 상태
Chapter 02

Scikit-Learn 소개

2.1 Scikit-Learn이란?

Scikit-Learn(사이킷런)은 파이썬 기반의 오픈소스 머신러닝 라이브러리입니다. 2007년 David Cournapeau가 Google Summer of Code 프로젝트로 시작했으며, 현재는 전 세계에서 가장 널리 사용되는 범용 머신러닝 라이브러리로 자리 잡았습니다. 2025년 12월 기준 최신 버전은 1.8.0입니다.

2.2 왜 Scikit-Learn인가?

딥러닝이 유행하는 시대에도 Scikit-Learn이 가장 먼저 배워야 할 라이브러리인 이유가 있습니다.

  • 일관된 API 설계 : 모든 알고리즘이 fit()predict()score()라는 동일한 패턴을 따릅니다. 하나를 배우면 나머지를 금방 익힙니다.
  • 풍부한 알고리즘 : 회귀, 분류, 군집화, 차원 축소, 전처리, 모델 선택 등 머신러닝에 필요한 거의 모든 기능을 제공합니다.
  • 훌륭한 문서 : 공식 문서의 품질이 매우 높으며, 예제와 수학적 배경을 함께 설명합니다.
  • NumPy/Pandas 호환 : 파이썬 데이터 과학 생태계와 완벽하게 호환됩니다.
  • 실무에서 충분 : 정형 데이터(표 형태 데이터) 분석에서는 딥러닝보다 Scikit-Learn 알고리즘이 더 좋은 성능을 내는 경우가 많습니다.

2.3 Scikit-Learn의 주요 모듈

모듈기능주요 클래스/함수
sklearn.datasets내장 데이터셋 제공load_iris, load_digits, make_classification
sklearn.preprocessing데이터 전처리StandardScaler, MinMaxScaler, LabelEncoder
sklearn.model_selection모델 선택 · 평가train_test_split, cross_val_score, GridSearchCV
sklearn.linear_model선형 모델LinearRegression, LogisticRegression, Ridge
sklearn.tree결정 트리DecisionTreeClassifier, DecisionTreeRegressor
sklearn.ensemble앙상블 모델RandomForestClassifier, GradientBoostingClassifier
sklearn.svm서포트 벡터 머신SVC, SVR
sklearn.neighborsK-최근접 이웃KNeighborsClassifier, KNeighborsRegressor
sklearn.cluster군집화KMeans, DBSCAN, AgglomerativeClustering
sklearn.decomposition차원 축소PCA, TruncatedSVD
sklearn.metrics성능 평가 지표accuracy_score, mean_squared_error, confusion_matrix
sklearn.pipeline파이프라인Pipeline, make_pipeline

2.4 Scikit-Learn의 일관된 API 패턴

Scikit-Learn의 가장 큰 강점은 어떤 알고리즘이든 동일한 패턴으로 사용한다는 점입니다. 아래 코드를 먼저 한 번 훑어보세요. 지금 이해가 안 되어도 전혀 괜찮습니다.

Python
# 모든 scikit-learn 모델은 이 3단계를 따릅니다

# 1단계: 모델 객체 생성
model = SomeAlgorithm(hyperparameter=value)

# 2단계: 학습 (훈련 데이터를 먹여줌)
model.fit(X_train, y_train)

# 3단계: 예측 (새 데이터에 대한 결과)
predictions = model.predict(X_test)

# (선택) 성능 평가
score = model.score(X_test, y_test)
Tip! 위의 패턴만 기억하세요. 선형 회귀든, 랜덤 포레스트든, SVM이든 모두 fit()predict()score()입니다. 이것이 Scikit-Learn이 사랑받는 핵심 이유입니다.
Chapter 03

환경 설정

3.1 파이썬 설치 확인

Scikit-Learn은 파이썬 라이브러리이므로 먼저 파이썬이 설치되어 있어야 합니다. 파이썬 3.9 이상을 권장합니다.

Bash
# 파이썬 버전 확인
python --version
# 또는
python3 --version

3.2 Scikit-Learn 설치

Bash
# pip로 설치 (가장 일반적)
pip install scikit-learn

# 관련 라이브러리 함께 설치 (권장)
pip install numpy pandas matplotlib scikit-learn

# conda로 설치 (Anaconda 사용자)
conda install scikit-learn

# 특정 버전 설치
pip install scikit-learn==1.8.0

3.3 설치 확인

Python
import sklearn
print(sklearn.__version__)
# 출력: 1.8.0

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

print("NumPy:", np.__version__)
print("Pandas:", pd.__version__)
print("모든 라이브러리가 정상 설치되었습니다!")

3.4 실습 환경 추천

환경특징추천 대상
Jupyter Notebook셀 단위 실행, 시각화 편리입문자, 데이터 분석
Google Colab설치 불필요, 무료 GPU환경 설정이 어려운 분
VS Code강력한 에디터, 디버깅 편리개발자
PyCharmJetBrains IDE, 자동완성 우수프로 개발자
입문자 추천! Google Colab(colab.research.google.com)은 아무것도 설치할 필요 없이 브라우저에서 바로 파이썬과 Scikit-Learn을 사용할 수 있습니다. 이 튜토리얼의 모든 예제를 Colab에서 실행할 수 있습니다.

3.5 이 튜토리얼에서 사용하는 import 모음

각 챕터에서 반복하지 않도록, 이 튜토리얼 전체에서 공통으로 사용하는 import를 미리 정리합니다.

Python
# ===== 공통 import =====
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 데이터셋
from sklearn.datasets import (
    load_iris, load_wine, load_breast_cancer,
    load_diabetes, fetch_california_housing,
    make_classification, make_regression, make_blobs
)

# 전처리
from sklearn.preprocessing import StandardScaler, MinMaxScaler, LabelEncoder

# 데이터 분할
from sklearn.model_selection import train_test_split

# 평가 지표
from sklearn.metrics import (
    accuracy_score, precision_score, recall_score, f1_score,
    confusion_matrix, classification_report,
    mean_squared_error, mean_absolute_error, r2_score
)

# 시각화 설정
plt.rcParams['font.family'] = 'Malgun Gothic'  # Windows 한글
plt.rcParams['axes.unicode_minus'] = False
plt.style.use('dark_background')  # 어두운 배경 스타일
Chapter 04

데이터셋 다루기

4.1 Scikit-Learn 내장 데이터셋

Scikit-Learn은 학습용 데이터셋을 기본으로 제공합니다. 별도의 파일 없이도 바로 머신러닝 실습을 시작할 수 있어 매우 편리합니다.

데이터셋함수유형샘플 수특성 수설명
Iris (붓꽃)load_iris()분류15043종 붓꽃 품종 분류
Wine (와인)load_wine()분류178133종 와인 품종 분류
Breast Cancerload_breast_cancer()분류56930유방암 양성/악성 분류
Digits (숫자)load_digits()분류1,79764손글씨 숫자(0~9) 인식
Diabetes (당뇨)load_diabetes()회귀44210당뇨 진행도 예측
California Housingfetch_california_housing()회귀20,6408캘리포니아 집값 예측

4.2 데이터셋 로드와 구조 파악

Python
from sklearn.datasets import load_iris

# 데이터셋 로드
iris = load_iris()

# 데이터셋 구조 확인 (Bunch 객체 = 딕셔너리와 비슷)
print("키 목록:", iris.keys())
# dict_keys(['data', 'target', 'frame', 'target_names',
#            'DESCR', 'feature_names', 'filename', 'data_module'])

# 특성 데이터 (X) - 2D 배열 (150행 × 4열)
print("data 형태:", iris.data.shape)      # (150, 4)
print("data 타입:", type(iris.data))    # numpy.ndarray

# 타겟 데이터 (y) - 1D 배열 (150개)
print("target 형태:", iris.target.shape)  # (150,)
print("타겟 값:", np.unique(iris.target)) # [0 1 2]

# 특성 이름과 타겟 이름
print("특성 이름:", iris.feature_names)
# ['sepal length (cm)', 'sepal width (cm)',
#  'petal length (cm)', 'petal width (cm)']

print("타겟 이름:", iris.target_names)
# ['setosa' 'versicolor' 'virginica']

# 데이터셋 설명 보기
print(iris.DESCR[:500])
data vs target
data는 모델에 입력되는 특성(Feature) 데이터, 즉 X입니다. target은 예측하고자 하는 정답(Label) 데이터, 즉 y입니다. 머신러닝은 X → y의 관계를 학습하는 것입니다.

4.3 Pandas DataFrame으로 변환

NumPy 배열보다 Pandas DataFrame이 데이터 탐색에 훨씬 편합니다. 컬럼 이름도 보이고, 통계 요약도 쉽습니다.

Python
# DataFrame으로 변환
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['target'] = iris.target
df['species'] = df['target'].map({
    0: 'setosa',
    1: 'versicolor',
    2: 'virginica'
})

# 처음 5행 확인
print(df.head())

# 기본 통계 요약
print(df.describe())

# 정보 확인 (컬럼 타입, 결측치 등)
print(df.info())

# 클래스별 데이터 수
print(df['species'].value_counts())
실행 결과 (head)
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) target species 0 5.1 3.5 1.4 0.2 0 setosa 1 4.9 3.0 1.4 0.2 0 setosa 2 4.7 3.2 1.3 0.2 0 setosa 3 4.6 3.1 1.5 0.2 0 setosa 4 5.0 3.6 1.4 0.2 0 setosa

4.4 인공 데이터셋 생성

특정 조건의 데이터를 직접 만들어 실험할 수 있습니다. 알고리즘의 동작을 이해하거나, 프로토타이핑에 유용합니다.

Python
from sklearn.datasets import make_classification, make_regression, make_blobs

# 분류용 인공 데이터 (1000샘플, 10특성, 2클래스)
X, y = make_classification(
    n_samples=1000,
    n_features=10,
    n_informative=5,     # 실제 유의미한 특성 수
    n_redundant=2,       # 중복 특성 수
    n_classes=2,          # 클래스 수
    random_state=42
)
print("분류 데이터:", X.shape, y.shape)

# 회귀용 인공 데이터 (500샘플, 5특성)
X, y = make_regression(
    n_samples=500,
    n_features=5,
    noise=10,             # 노이즈 정도
    random_state=42
)
print("회귀 데이터:", X.shape, y.shape)

# 군집화용 데이터 (300샘플, 3개 클러스터)
X, y = make_blobs(
    n_samples=300,
    centers=3,            # 클러스터 수
    cluster_std=1.0,      # 클러스터 표준편차
    random_state=42
)
print("군집 데이터:", X.shape, y.shape)

4.5 외부 데이터 사용하기

Python
# CSV 파일 로드 (Pandas 활용)
df = pd.read_csv('my_data.csv')

# 특성(X)과 타겟(y)으로 분리
X = df.drop('target_column', axis=1)  # target 열을 제외한 나머지
y = df['target_column']                # target 열만

# NumPy 배열로 변환 (선택)
X = X.values
y = y.values
Chapter 05

데이터 전처리

5.1 왜 전처리가 필요한가?

현실의 데이터는 결측치(빠진 값), 이상치(극단적으로 튀는 값), 서로 다른 스케일(키는 170cm, 몸무게는 70kg)을 가지고 있습니다. 대부분의 머신러닝 알고리즘은 깨끗하고 동일한 척도의 데이터를 입력받아야 제대로 된 성능을 발휘합니다. 데이터 전처리는 머신러닝의 성패를 좌우하는 가장 중요한 단계입니다.

5.2 Train-Test 분할

모델을 학습하는 데이터와 평가하는 데이터를 반드시 분리해야 합니다. 시험 문제를 미리 알고 공부하면 진짜 실력을 알 수 없는 것과 같은 이치입니다.

Python
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris

# 데이터 준비
iris = load_iris()
X, y = iris.data, iris.target

# 학습용 80% / 테스트용 20%로 분할
X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,       # 테스트 비율 (20%)
    random_state=42,     # 재현성을 위한 시드
    stratify=y            # 클래스 비율 유지 (중요!)
)

print(f"전체: {X.shape[0]}개")
print(f"학습: {X_train.shape[0]}개")
print(f"테스트: {X_test.shape[0]}개")
실행 결과
전체: 150개 학습: 120개 테스트: 30개
stratify 파라미터의 중요성
분류 문제에서 stratify=y를 지정하면, 학습 세트와 테스트 세트에 각 클래스(0, 1, 2)가 원본과 동일한 비율로 포함됩니다. 예를 들어, 원본에 클래스 A가 70%, B가 30%라면, 분할 후에도 같은 비율이 유지됩니다. 이를 생략하면 특정 클래스가 편향될 수 있습니다.

5.3 특성 스케일링 (Feature Scaling)

특성의 단위와 범위가 다르면 일부 알고리즘(KNN, SVM, 경사하강법 기반 모델)의 성능이 크게 저하됩니다. 예를 들어, "나이(0~100)"와 "연봉(0~100,000,000)" 두 특성이 있다면, 연봉의 숫자가 훨씬 크기 때문에 모델이 연봉에만 집중하게 됩니다.

StandardScaler (표준화)

각 특성을 평균 0, 표준편차 1로 변환합니다. 가장 많이 사용되는 스케일링 방법입니다.

Python
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()

# 학습 데이터로 fit (평균, 표준편차 계산) + 변환
X_train_scaled = scaler.fit_transform(X_train)

# 테스트 데이터는 transform만! (학습 데이터의 통계로 변환)
X_test_scaled = scaler.transform(X_test)

print("스케일링 전 평균:", X_train[:, 0].mean().round(2))
print("스케일링 후 평균:", X_train_scaled[:, 0].mean().round(2))
print("스케일링 후 표준편차:", X_train_scaled[:, 0].std().round(2))
실행 결과
스케일링 전 평균: 5.86 스케일링 후 평균: 0.0 스케일링 후 표준편차: 1.0
핵심 주의! 테스트 데이터에는 절대 fit_transform()을 쓰면 안 됩니다. 반드시 transform()만 사용하세요. fit()은 학습 데이터의 통계(평균, 표준편차)를 기억하는 과정입니다. 테스트 데이터에도 fit하면, 미래의 정보를 미리 들여다보는 것이 되어 데이터 누출(Data Leakage)이 발생합니다.

MinMaxScaler (정규화)

모든 값을 0~1 범위로 변환합니다. 이미지 데이터나 신경망에서 자주 사용됩니다.

Python
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
X_train_minmax = scaler.fit_transform(X_train)
X_test_minmax = scaler.transform(X_test)

print("최소값:", X_train_minmax.min())  # 0.0
print("최대값:", X_train_minmax.max())  # 1.0

5.4 어떤 스케일러를 사용해야 할까?

스케일러변환 결과적합한 상황
StandardScaler평균 0, 분산 1이상치가 적은 경우, 대부분의 알고리즘
MinMaxScaler0~1 범위고정된 범위가 필요한 경우, 신경망
RobustScaler중앙값 0, IQR 기반이상치가 많은 경우

5.5 결측치 처리

Python
from sklearn.impute import SimpleImputer

# 평균값으로 결측치 대체
imputer = SimpleImputer(strategy='mean')
X_train_imputed = imputer.fit_transform(X_train)
X_test_imputed = imputer.transform(X_test)

# strategy 옵션들:
# 'mean'   : 평균값 (숫자형 기본)
# 'median' : 중앙값 (이상치가 있을 때)
# 'most_frequent' : 최빈값 (범주형)
# 'constant' : 지정한 상수값

5.6 범주형 변수 인코딩

머신러닝 모델은 숫자만 이해합니다. 문자열로 된 범주형 변수('남', '여', '서울', '부산')는 숫자로 변환해야 합니다.

Python
from sklearn.preprocessing import LabelEncoder, OneHotEncoder

# ① LabelEncoder : 라벨을 0, 1, 2, ...로 변환
le = LabelEncoder()
colors = ['red', 'blue', 'green', 'red', 'blue']
encoded = le.fit_transform(colors)
print(encoded)  # [2 0 1 2 0]

# 복원
print(le.inverse_transform(encoded))  # ['red' 'blue' 'green' 'red' 'blue']

# ② OneHotEncoder : 원-핫 인코딩 (더 많이 사용)
# Pandas get_dummies가 더 간편합니다
df = pd.DataFrame({'color': ['red', 'blue', 'green', 'red']})
df_encoded = pd.get_dummies(df, columns=['color'], drop_first=True)
print(df_encoded)
실행 결과 (원-핫 인코딩)
color_green color_red 0 False True 1 False False 2 True False 3 False True
LabelEncoder vs OneHotEncoder
LabelEncoder는 순서가 있는(ordinal) 범주에, OneHotEncoder는 순서가 없는(nominal) 범주에 사용합니다. 예를 들어, 학력(초졸 < 중졸 < 고졸 < 대졸)은 LabelEncoder가 적합하고, 색상(빨강, 파랑, 초록)은 OneHotEncoder가 적합합니다. LabelEncoder로 색상을 0, 1, 2로 변환하면 모델이 "2 > 1 > 0" 즉 "초록 > 파랑 > 빨강"이라는 잘못된 순서를 학습할 수 있습니다.
Chapter 06

학습과 예측 - 기본 흐름 완전 마스터

6.1 Scikit-Learn의 핵심 3단계

이 챕터에서는 Chapter 02에서 소개한 fit()predict()score() 패턴을 실제 데이터로 처음부터 끝까지 실습합니다. 이 패턴을 완벽히 이해하면 어떤 알고리즘이든 자유자재로 사용할 수 있습니다.

Python
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

# ============================
# STEP 0 : 데이터 준비
# ============================
iris = load_iris()
X, y = iris.data, iris.target

# 학습(80%) / 테스트(20%) 분할
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# ============================
# STEP 1 : 모델 생성
# ============================
# K-최근접 이웃 분류기 (k=5)
model = KNeighborsClassifier(n_neighbors=5)

# ============================
# STEP 2 : 학습 (fit)
# ============================
# 학습 데이터를 모델에 전달하여 패턴을 학습시킵니다
model.fit(X_train, y_train)

# ============================
# STEP 3 : 예측 (predict)
# ============================
# 테스트 데이터로 예측값을 생성합니다
y_pred = model.predict(X_test)

print("실제값 :", y_test[:10])
print("예측값 :", y_pred[:10])

# ============================
# STEP 4 : 평가 (score)
# ============================
accuracy = accuracy_score(y_test, y_pred)
print(f"\n정확도: {accuracy:.4f}")
print(f"정확도: {accuracy * 100:.1f}%")

# model.score()로도 동일한 결과
print(f"score(): {model.score(X_test, y_test):.4f}")
실행 결과
실제값 : [1 0 2 1 1 0 1 2 1 1] 예측값 : [1 0 2 1 1 0 1 2 1 1] 정확도: 1.0000 정확도: 100.0% score(): 1.0000

6.2 새로운 데이터 예측

학습된 모델에 완전히 새로운 데이터를 넣어 예측해 봅시다.

Python
# 새로운 붓꽃 데이터 (꽃받침 길이, 꽃받침 폭, 꽃잎 길이, 꽃잎 폭)
new_flower = [[5.0, 3.5, 1.5, 0.3]]
prediction = model.predict(new_flower)
print(f"예측 클래스: {prediction[0]}")
print(f"예측 품종: {iris.target_names[prediction[0]]}")

# 여러 개 동시 예측
new_flowers = [
    [5.0, 3.5, 1.5, 0.3],  # 아마 setosa?
    [6.5, 3.0, 5.2, 2.0],  # 아마 virginica?
    [5.8, 2.7, 4.1, 1.0],  # 아마 versicolor?
]
predictions = model.predict(new_flowers)
for flower, pred in zip(new_flowers, predictions):
    print(f"  {flower} → {iris.target_names[pred]}")
실행 결과
예측 클래스: 0 예측 품종: setosa [5.0, 3.5, 1.5, 0.3] → setosa [6.5, 3.0, 5.2, 2.0] → virginica [5.8, 2.7, 4.1, 1.0] → versicolor
축하합니다! 여러분은 방금 첫 번째 머신러닝 모델을 만들고, 학습시키고, 예측까지 완료했습니다. 이후 챕터에서 다양한 알고리즘을 배우지만, 기본 흐름은 항상 동일합니다: 데이터 준비 → 모델 생성 → fit → predict → 평가.
Chapter 07

선형 회귀 (Linear Regression)

7.1 선형 회귀란?

선형 회귀는 입력(X)과 출력(y) 사이의 선형 관계를 찾는 가장 기본적인 회귀 알고리즘입니다. 중학교 수학에서 배운 일차 함수 y = ax + b를 떠올리면 됩니다. 데이터에 가장 잘 맞는 직선(또는 초평면)을 찾아 새로운 입력에 대한 연속적인 값을 예측합니다.

예를 들어, "집의 면적(X)"으로 "집값(y)"을 예측하거나, "공부 시간(X)"으로 "시험 점수(y)"를 예측하는 문제에 적합합니다.

7.2 실습 : 당뇨 진행도 예측

Python
from sklearn.datasets import load_diabetes
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

# 데이터 준비
diabetes = load_diabetes()
X, y = diabetes.data, diabetes.target
print(f"데이터 형태: X={X.shape}, y={y.shape}")
print(f"특성 이름: {diabetes.feature_names}")

# 분할
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 모델 학습
model = LinearRegression()
model.fit(X_train, y_train)

# 예측
y_pred = model.predict(X_test)

# 평가
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)

print(f"\n=== 선형 회귀 결과 ===")
print(f"MSE  (평균 제곱 오차): {mse:.2f}")
print(f"RMSE (제곱근 MSE)   : {rmse:.2f}")
print(f"R² Score           : {r2:.4f}")

# 회귀 계수 (각 특성의 기여도) 확인
print(f"\n절편(intercept): {model.intercept_:.2f}")
for name, coef in zip(diabetes.feature_names, model.coef_):
    print(f"  {name:>5s}: {coef:>8.2f}")
실행 결과
데이터 형태: X=(442, 10), y=(442,) 특성 이름: ['age', 'sex', 'bmi', 'bp', 's1', 's2', 's3', 's4', 's5', 's6'] === 선형 회귀 결과 === MSE (평균 제곱 오차): 2900.19 RMSE (제곱근 MSE) : 53.85 R² Score : 0.4526 절편(intercept): 151.35 age: -60.40 sex: -226.08 bmi: 529.38 bp: 339.19 s1: -814.13 s2: 492.81 s3: 115.51 s4: 245.54 s5: 633.68 s6: 67.25

7.3 회귀 평가 지표 이해

지표수식 의미좋은 값해석
MSE오차의 제곱 평균0에 가까울수록큰 오차에 더 큰 벌점
RMSEMSE의 제곱근0에 가까울수록원래 단위로 해석 가능
MAE오차 절대값의 평균0에 가까울수록이상치 영향 적음
R² Score설명된 분산 비율1에 가까울수록1 = 완벽, 0 = 평균 수준

7.4 릿지(Ridge)와 라쏘(Lasso) 회귀

기본 선형 회귀에 규제(Regularization)를 추가한 변형입니다. 과적합을 방지하는 효과가 있습니다.

Python
from sklearn.linear_model import Ridge, Lasso

# Ridge 회귀 (L2 규제 : 계수를 작게 유지)
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
print(f"Ridge R²: {ridge.score(X_test, y_test):.4f}")

# Lasso 회귀 (L1 규제 : 불필요한 특성의 계수를 0으로)
lasso = Lasso(alpha=1.0)
lasso.fit(X_train, y_train)
print(f"Lasso R²: {lasso.score(X_test, y_test):.4f}")

# Lasso는 특성 선택 효과가 있음
print(f"\nLasso가 0으로 만든 특성 수: {sum(lasso.coef_ == 0)}")
Ridge vs Lasso 정리
Ridge(릿지)는 모든 특성을 유지하되 계수 크기를 줄이고, Lasso(라쏘)는 중요하지 않은 특성의 계수를 아예 0으로 만들어 자동으로 특성 선택(Feature Selection)을 수행합니다. alpha 값이 클수록 규제가 강합니다.
Chapter 08

로지스틱 회귀 (Logistic Regression)

8.1 이름은 "회귀"지만 "분류" 알고리즘

로지스틱 회귀는 이름에 "회귀"가 들어가지만, 실제로는 분류 알고리즘입니다. 선형 회귀의 결과를 시그모이드(Sigmoid) 함수에 통과시켜 0~1 사이의 확률로 변환하고, 이 확률을 기반으로 클래스를 분류합니다.

예를 들어, 출력이 0.8이면 "양성(1)일 확률이 80%"로 해석하고, 0.5 이상이면 양성, 미만이면 음성으로 분류합니다.

8.2 실습 : 유방암 분류

Python
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report

# 데이터 준비
cancer = load_breast_cancer()
X, y = cancer.data, cancer.target
print(f"데이터 형태: {X.shape}")
print(f"클래스: {cancer.target_names}")  # ['malignant' 'benign']

# 분할
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 스케일링 (로지스틱 회귀는 스케일링이 중요합니다)
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

# 모델 학습
model = LogisticRegression(max_iter=10000, random_state=42)
model.fit(X_train_s, y_train)

# 예측 및 평가
y_pred = model.predict(X_test_s)
print(f"\n정확도: {accuracy_score(y_test, y_pred):.4f}")
print("\n상세 리포트:")
print(classification_report(y_test, y_pred,
      target_names=cancer.target_names))
실행 결과
데이터 형태: (569, 30) 클래스: ['malignant' 'benign'] 정확도: 0.9825 상세 리포트: precision recall f1-score support malignant 0.98 0.98 0.98 42 benign 0.99 0.99 0.99 72 accuracy 0.98 114 macro avg 0.98 0.98 0.98 114 weighted avg 0.98 0.98 0.98 114

8.3 확률 예측

로지스틱 회귀의 강점은 단순히 클래스를 예측하는 것뿐만 아니라, 각 클래스에 속할 확률도 알려준다는 것입니다.

Python
# predict_proba(): 각 클래스의 확률 반환
y_proba = model.predict_proba(X_test_s)

# 처음 5개 샘플의 확률
for i in range(5):
    print(f"샘플 {i}: 악성={y_proba[i][0]:.4f}, "
          f"양성={y_proba[i][1]:.4f} → "
          f"예측={cancer.target_names[y_pred[i]]}")
실행 결과
샘플 0: 악성=0.0004, 양성=0.9996 → 예측=benign 샘플 1: 악성=0.9995, 양성=0.0005 → 예측=malignant 샘플 2: 악성=0.0002, 양성=0.9998 → 예측=benign 샘플 3: 악성=0.0005, 양성=0.9995 → 예측=benign 샘플 4: 악성=0.0198, 양성=0.9802 → 예측=benign
Chapter 09

K-최근접 이웃 (KNN)

9.1 KNN의 직관적 이해

KNN(K-Nearest Neighbors)은 가장 직관적인 머신러닝 알고리즘입니다. "주변에 어떤 이웃이 많은가?"를 보고 판단합니다. 새로운 데이터가 들어오면, 학습 데이터 중 가장 가까운 K개의 이웃을 찾아 다수결로 분류합니다.

일상에서의 비유: 새로 이사 온 동네에서 "이 근처에 맛집이 많으면 이 동네는 맛집 동네일 거야"라고 판단하는 것과 같습니다.

9.2 핵심 하이퍼파라미터

파라미터설명기본값
n_neighbors이웃의 수 (K)5홀수 권장 (동점 방지)
weights이웃의 가중치'uniform''distance'면 가까운 이웃에 더 큰 가중치
metric거리 계산 방식'minkowski'유클리디안(p=2), 맨해튼(p=1)

9.3 실습과 K값에 따른 성능 변화

Python
from sklearn.datasets import load_wine
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 와인 데이터 준비
wine = load_wine()
X, y = wine.data, wine.target

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 스케일링 (KNN은 거리 기반이므로 반드시 스케일링!)
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

# K값 1~20까지 변화시키며 정확도 비교
k_range = range(1, 21)
scores = []

for k in k_range:
    knn = KNeighborsClassifier(n_neighbors=k)
    knn.fit(X_train_s, y_train)
    score = knn.score(X_test_s, y_test)
    scores.append(score)
    print(f"K={k:2d} → 정확도: {score:.4f}")

best_k = list(k_range)[scores.index(max(scores))]
print(f"\n최적 K: {best_k} (정확도: {max(scores):.4f})")
KNN은 스케일링이 필수! KNN은 데이터 간의 "거리"를 계산하여 분류하기 때문에, 특성의 단위가 다르면 큰 값을 가진 특성이 결과를 지배합니다. 반드시 StandardScaler 또는 MinMaxScaler로 스케일링하세요.
Chapter 10

결정 트리 (Decision Tree)

10.1 결정 트리의 직관

결정 트리는 스무고개 게임과 같습니다. "이 데이터의 특성 A가 5보다 큰가?" → "특성 B가 3 이하인가?" 처럼 예/아니오 질문을 반복하여 최종 결론에 도달합니다. 사람이 이해하기 가장 쉬운 알고리즘이며, 시각적으로 결과를 표현할 수 있습니다.

10.2 실습 : Iris 분류

Python
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier, export_text
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report

# 데이터 준비
iris = load_iris()
X, y = iris.data, iris.target

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 결정 트리 모델 (깊이 3으로 제한하여 과적합 방지)
tree = DecisionTreeClassifier(
    max_depth=3,            # 트리의 최대 깊이
    min_samples_split=5,    # 분할에 필요한 최소 샘플 수
    random_state=42
)
tree.fit(X_train, y_train)

# 예측 및 평가
y_pred = tree.predict(X_test)
print(f"정확도: {accuracy_score(y_test, y_pred):.4f}")

# 트리 구조를 텍스트로 출력
tree_rules = export_text(tree, feature_names=iris.feature_names)
print("\n결정 트리 규칙:")
print(tree_rules)
실행 결과
정확도: 0.9667 결정 트리 규칙: |--- petal width (cm) <= 0.75 | |--- class: 0 |--- petal width (cm) > 0.75 | |--- petal width (cm) <= 1.75 | | |--- petal length (cm) <= 4.95 | | | |--- class: 1 | | |--- petal length (cm) > 4.95 | | | |--- class: 2 | |--- petal width (cm) > 1.75 | | |--- petal length (cm) <= 4.85 | | | |--- class: 2 | | |--- petal length (cm) > 4.85 | | | |--- class: 2

10.3 특성 중요도 (Feature Importance)

결정 트리의 큰 장점 중 하나는 각 특성이 예측에 얼마나 기여하는지 알려준다는 것입니다.

Python
# 특성 중요도 확인
importances = tree.feature_importances_
for name, imp in sorted(
    zip(iris.feature_names, importances),
    key=lambda x: x[1],
    reverse=True
):
    print(f"  {name:20s}: {imp:.4f} {'█' * int(imp * 50)}")
실행 결과
petal width (cm) : 0.5869 █████████████████████████████ petal length (cm) : 0.4131 ████████████████████ sepal length (cm) : 0.0000 sepal width (cm) : 0.0000
과적합 주의! 결정 트리는 제한 없이 깊게 성장시키면 훈련 데이터를 완벽히 외워서(과적합) 새 데이터에서 성능이 떨어집니다. max_depth, min_samples_split, min_samples_leaf 등의 파라미터로 트리의 복잡도를 제한하세요.
Chapter 11

앙상블 - 랜덤 포레스트

11.1 앙상블이란?

앙상블(Ensemble)은 "여러 모델의 예측을 결합하여 더 나은 결과를 얻는 기법"입니다. 한 명의 전문가보다 여러 전문가의 의견을 종합하면 더 정확한 판단을 할 수 있는 것과 같은 원리입니다. 이를 "집단 지성(Wisdom of Crowds)"이라고도 합니다.

11.2 랜덤 포레스트

랜덤 포레스트(Random Forest)는 여러 개의 결정 트리를 만들어 다수결(분류) 또는 평균(회귀)으로 최종 결과를 내는 앙상블 기법입니다. 각 트리는 데이터의 일부(Bootstrap)와 특성의 일부를 무작위로 사용하기 때문에 다양한 관점을 제공합니다.

Python
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report

# 데이터 준비
cancer = load_breast_cancer()
X, y = cancer.data, cancer.target
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 랜덤 포레스트 (100개의 트리)
rf = RandomForestClassifier(
    n_estimators=100,     # 트리 개수
    max_depth=10,          # 각 트리의 최대 깊이
    min_samples_split=5,  # 분할 최소 샘플
    random_state=42,
    n_jobs=-1              # 모든 CPU 코어 사용
)
rf.fit(X_train, y_train)

# 평가
y_pred = rf.predict(X_test)
print(f"랜덤 포레스트 정확도: {accuracy_score(y_test, y_pred):.4f}")
print(classification_report(y_test, y_pred,
      target_names=cancer.target_names))

# 상위 10개 중요 특성
print("=== 특성 중요도 TOP 10 ===")
feat_imp = sorted(
    zip(cancer.feature_names, rf.feature_importances_),
    key=lambda x: x[1], reverse=True
)
for name, imp in feat_imp[:10]:
    print(f"  {name:25s}: {imp:.4f}")
실행 결과
랜덤 포레스트 정확도: 0.9649 === 특성 중요도 TOP 10 === worst radius : 0.1440 worst concave points : 0.1418 mean concave points : 0.1152 worst perimeter : 0.1056 mean perimeter : 0.0598 mean radius : 0.0537 worst area : 0.0506 mean area : 0.0380 area error : 0.0379 mean concavity : 0.0344

11.3 그래디언트 부스팅

랜덤 포레스트가 여러 트리를 "동시에" 만들었다면, 그래디언트 부스팅은 이전 트리의 실수를 보완하는 트리를 "순차적으로" 추가합니다. 일반적으로 랜덤 포레스트보다 높은 성능을 내지만, 학습 시간이 더 오래 걸립니다.

Python
from sklearn.ensemble import GradientBoostingClassifier

gb = GradientBoostingClassifier(
    n_estimators=100,
    learning_rate=0.1,   # 학습률 (작을수록 신중, 느림)
    max_depth=3,
    random_state=42
)
gb.fit(X_train, y_train)
print(f"그래디언트 부스팅 정확도: {gb.score(X_test, y_test):.4f}")
실무 Tip! 정형 데이터(표 형태)에서는 XGBoost, LightGBM, CatBoost 같은 고성능 그래디언트 부스팅 라이브러리가 Kaggle 대회에서 압도적 성능을 보여줍니다. Scikit-Learn의 GradientBoosting으로 기본 개념을 익힌 뒤, 이들 라이브러리로 넘어가는 것을 추천합니다.
Chapter 12

서포트 벡터 머신 (SVM)

12.1 SVM의 핵심 아이디어

SVM(Support Vector Machine)은 두 클래스를 가장 "넓은 간격(마진)"으로 분리하는 경계선(결정 경계)을 찾는 알고리즘입니다. 두 클래스 사이에 가능한 한 넓은 도로를 깔아서, 새로운 데이터가 어느 쪽에 속하는지 판단하는 것으로 비유할 수 있습니다.

핵심은 "커널 트릭(Kernel Trick)"입니다. 직선으로 분리할 수 없는 데이터도 고차원 공간으로 매핑하면 분리할 수 있게 됩니다.

12.2 실습

Python
from sklearn.svm import SVC
from sklearn.datasets import load_wine
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

wine = load_wine()
X, y = wine.data, wine.target
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# SVM은 반드시 스케일링!
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

# 다양한 커널 비교
kernels = ['linear', 'rbf', 'poly']
for kernel in kernels:
    svm = SVC(kernel=kernel, random_state=42)
    svm.fit(X_train_s, y_train)
    score = svm.score(X_test_s, y_test)
    print(f"  커널: {kernel:8s} → 정확도: {score:.4f}")
실행 결과
커널: linear → 정확도: 0.9722 커널: rbf → 정확도: 0.9722 커널: poly → 정확도: 0.9722
SVM 주요 파라미터
C는 규제 파라미터로, 값이 클수록 마진 위반을 허용하지 않습니다(과적합 위험). gamma는 RBF 커널의 영향 범위를 조절합니다. kernel은 'linear'(선형), 'rbf'(가우시안), 'poly'(다항식) 등을 선택할 수 있습니다. SVM은 대량 데이터(수만 건 이상)에서는 학습이 느릴 수 있습니다.
Chapter 13

모델 평가 지표 완전 정리

13.1 분류 평가 지표

"정확도 98%면 좋은 모델일까요?" 반드시 그렇지는 않습니다. 100명 중 1명만 암 환자인 데이터에서, "모두 정상"이라고 예측하면 정확도는 99%이지만, 정작 암 환자는 하나도 찾지 못합니다. 상황에 맞는 평가 지표를 선택하는 것이 중요합니다.

지표설명수식 의미중요한 경우
Accuracy (정확도)전체 중 맞춘 비율(TP+TN) / 전체클래스 균형일 때
Precision (정밀도)양성 예측 중 실제 양성TP / (TP+FP)오탐(스팸 필터)
Recall (재현율)실제 양성 중 맞춘 비율TP / (TP+FN)미탐(암 진단)
F1 ScorePrecision과 Recall의 조화평균2 × P×R / (P+R)불균형 데이터

13.2 혼동 행렬 (Confusion Matrix)

Python
from sklearn.metrics import (
    confusion_matrix, classification_report,
    accuracy_score, precision_score, recall_score, f1_score
)
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    cancer.data, cancer.target,
    test_size=0.2, random_state=42, stratify=cancer.target
)

rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)

# 혼동 행렬
cm = confusion_matrix(y_test, y_pred)
print("혼동 행렬:")
print(cm)

# 상세 리포트 (한 번에 모든 지표 확인)
print("\n분류 리포트:")
print(classification_report(y_test, y_pred,
      target_names=['악성', '양성']))
실행 결과
혼동 행렬: [[39 3] [ 1 71]] 분류 리포트: precision recall f1-score support 악성 0.97 0.93 0.95 42 양성 0.96 0.99 0.97 72 accuracy 0.96 114 macro avg 0.97 0.96 0.96 114 weighted avg 0.96 0.96 0.96 114

13.3 회귀 평가 지표 코드

Python
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import numpy as np

# y_test, y_pred가 있다고 가정
mse  = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae  = mean_absolute_error(y_test, y_pred)
r2   = r2_score(y_test, y_pred)

print(f"MSE  : {mse:.4f}")
print(f"RMSE : {rmse:.4f}")
print(f"MAE  : {mae:.4f}")
print(f"R²   : {r2:.4f}")
어떤 지표를 써야 할까?
암 진단 → Recall (놓치면 안 됨, 미탐 최소화)
스팸 필터 → Precision (정상 메일을 스팸으로 보내면 안 됨, 오탐 최소화)
불균형 데이터 → F1 Score (Precision과 Recall의 균형)
집값 예측 → RMSE, R² Score
Chapter 14

교차 검증 (Cross Validation)

14.1 왜 교차 검증이 필요한가?

단순히 한 번의 Train-Test 분할로 평가하면, 그 특정 분할에 운 좋게 잘 맞는 결과가 나올 수 있습니다. 교차 검증은 데이터를 여러 번 다르게 나누어 평가함으로써, 모델의 일반화 성능을 더 신뢰성 있게 측정합니다.

14.2 K-Fold 교차 검증

데이터를 K개의 조각(Fold)으로 나누고, 각 조각을 한 번씩 테스트 세트로 사용하여 K번 학습-평가를 반복합니다. 최종 점수는 K번의 평균입니다.

Python
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
import numpy as np

iris = load_iris()
X, y = iris.data, iris.target

model = RandomForestClassifier(n_estimators=100, random_state=42)

# 5-Fold 교차 검증
scores = cross_val_score(
    model, X, y,
    cv=5,                   # 5개 Fold
    scoring='accuracy'     # 평가 지표
)

print("각 Fold의 정확도:", scores)
print(f"평균 정확도: {scores.mean():.4f}")
print(f"표준 편차 : {scores.std():.4f}")
print(f"신뢰 구간 : {scores.mean():.4f} ± {scores.std() * 2:.4f}")
실행 결과
각 Fold의 정확도: [0.96666667 0.96666667 0.93333333 0.96666667 1. ] 평균 정확도: 0.9667 표준 편차 : 0.0211 신뢰 구간 : 0.9667 ± 0.0422

14.3 여러 모델 비교

Python
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC

models = {
    'Logistic Regression': LogisticRegression(max_iter=10000),
    'KNN (k=5)'          : KNeighborsClassifier(n_neighbors=5),
    'Decision Tree'      : DecisionTreeClassifier(random_state=42),
    'Random Forest'      : RandomForestClassifier(random_state=42),
    'SVM (RBF)'          : SVC(random_state=42),
}

print(f"{'모델':25s} {'평균':>8s} {'표준편차':>8s}")
print("-" * 45)
for name, model in models.items():
    scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
    print(f"{name:25s} {scores.mean():>8.4f} {scores.std():>8.4f}")
실행 결과
모델 평균 표준편차 --------------------------------------------- Logistic Regression 0.9733 0.0249 KNN (k=5) 0.9667 0.0211 Decision Tree 0.9533 0.0327 Random Forest 0.9667 0.0211 SVM (RBF) 0.9733 0.0249
StratifiedKFold
분류 문제에서 cross_val_score는 기본적으로 StratifiedKFold를 사용합니다. 이는 각 Fold에서 클래스 비율이 원본과 동일하게 유지되도록 합니다. 회귀 문제에서는 일반 KFold가 사용됩니다.
Chapter 15

하이퍼파라미터 튜닝

15.1 하이퍼파라미터란?

하이퍼파라미터(Hyperparameter)는 모델이 학습하기 전에 사람이 직접 설정해야 하는 값입니다. 예를 들어, KNN의 K값, 랜덤 포레스트의 트리 개수, SVM의 C값 등입니다. 이 값을 어떻게 설정하느냐에 따라 모델 성능이 크게 달라집니다.

15.2 GridSearchCV - 모든 조합 탐색

가능한 모든 하이퍼파라미터 조합을 시도하여 가장 좋은 조합을 찾습니다. 확실하지만, 조합이 많으면 시간이 오래 걸립니다.

Python
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

# 데이터 준비
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
    cancer.data, cancer.target,
    test_size=0.2, random_state=42, stratify=cancer.target
)

# 탐색할 하이퍼파라미터 조합 정의
param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [3, 5, 10, None],
    'min_samples_split': [2, 5, 10],
}
# 총 조합 수: 3 × 4 × 3 = 36가지

# GridSearchCV 실행
grid_search = GridSearchCV(
    estimator=RandomForestClassifier(random_state=42),
    param_grid=param_grid,
    cv=5,                    # 5-Fold 교차 검증
    scoring='accuracy',
    n_jobs=-1,                # 전체 CPU 사용
    verbose=1                 # 진행 상황 출력
)
grid_search.fit(X_train, y_train)

# 결과 확인
print(f"\n최적 파라미터: {grid_search.best_params_}")
print(f"최고 교차검증 점수: {grid_search.best_score_:.4f}")
print(f"테스트 세트 점수: {grid_search.score(X_test, y_test):.4f}")

# 최적 모델 바로 사용
best_model = grid_search.best_estimator_
y_pred = best_model.predict(X_test)
실행 결과
Fitting 5 folds for each of 36 candidates, totalling 180 fits 최적 파라미터: {'max_depth': 10, 'min_samples_split': 2, 'n_estimators': 200} 최고 교차검증 점수: 0.9670 테스트 세트 점수: 0.9649

15.3 RandomizedSearchCV - 무작위 탐색

모든 조합 대신 무작위로 일부만 시도합니다. 파라미터 범위가 넓을 때 효율적입니다.

Python
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint, uniform

# 파라미터 분포 정의 (범위에서 랜덤 샘플링)
param_dist = {
    'n_estimators': randint(50, 500),
    'max_depth': randint(2, 20),
    'min_samples_split': randint(2, 20),
    'min_samples_leaf': randint(1, 10),
}

random_search = RandomizedSearchCV(
    estimator=RandomForestClassifier(random_state=42),
    param_distributions=param_dist,
    n_iter=50,              # 50번만 무작위 시도
    cv=5,
    scoring='accuracy',
    random_state=42,
    n_jobs=-1
)
random_search.fit(X_train, y_train)

print(f"최적 파라미터: {random_search.best_params_}")
print(f"최고 점수: {random_search.best_score_:.4f}")
GridSearch vs RandomizedSearch
파라미터 조합이 적을 때(수십~수백 개)는 GridSearchCV, 많을 때(수천 개 이상)는 RandomizedSearchCV를 사용하세요. 실무에서는 RandomizedSearchCV로 대략적인 범위를 좁힌 뒤, GridSearchCV로 미세 조정하는 2단계 전략이 효과적입니다.
Chapter 16

파이프라인 (Pipeline)

16.1 왜 파이프라인이 필요한가?

실제 머신러닝 작업에서는 전처리(스케일링, 인코딩) → 모델 학습 → 예측의 여러 단계를 거칩니다. 이 단계들을 일일이 따로 실행하면 코드가 복잡해지고, 실수(특히 데이터 누출)가 발생하기 쉽습니다.

파이프라인(Pipeline)은 이 모든 단계를 하나의 객체로 묶어서, fit() 한 번, predict() 한 번으로 모든 처리가 자동으로 이루어지게 합니다.

16.2 기본 파이프라인

Python
from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split, cross_val_score

wine = load_wine()
X, y = wine.data, wine.target
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 파이프라인 생성: 스케일링 → SVM
pipe = Pipeline([
    ('scaler', StandardScaler()),    # 1단계: 스케일링
    ('svm',    SVC(kernel='rbf'))     # 2단계: 모델
])

# 또는 간단히 make_pipeline 사용
pipe = make_pipeline(StandardScaler(), SVC(kernel='rbf'))

# fit 한 번으로 전처리 + 학습 완료!
pipe.fit(X_train, y_train)

# predict 한 번으로 전처리 + 예측 완료!
score = pipe.score(X_test, y_test)
print(f"파이프라인 정확도: {score:.4f}")

# 교차 검증도 파이프라인 그대로 사용
cv_scores = cross_val_score(pipe, X, y, cv=5)
print(f"교차검증 평균: {cv_scores.mean():.4f}")

16.3 파이프라인 + GridSearchCV

파이프라인의 진정한 위력은 GridSearchCV와 결합할 때 나타납니다. 전처리와 모델의 파라미터를 동시에 튜닝할 수 있습니다.

Python
from sklearn.model_selection import GridSearchCV

pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('svm', SVC())
])

# 파이프라인 내부 파라미터는 '단계이름__파라미터명' 형태로 접근
param_grid = {
    'svm__C': [0.1, 1, 10, 100],
    'svm__kernel': ['rbf', 'linear'],
    'svm__gamma': ['scale', 'auto', 0.01, 0.1],
}

grid = GridSearchCV(pipe, param_grid, cv=5, scoring='accuracy', n_jobs=-1)
grid.fit(X_train, y_train)

print(f"최적 파라미터: {grid.best_params_}")
print(f"최고 점수: {grid.best_score_:.4f}")
print(f"테스트 점수: {grid.score(X_test, y_test):.4f}")
파이프라인의 핵심 이점
파이프라인을 사용하면 교차 검증 시 각 Fold마다 전처리가 독립적으로 수행되어 데이터 누출을 완벽히 방지합니다. 파이프라인 없이 전체 데이터에 먼저 fit_transform()을 한 뒤 교차 검증을 하면, 테스트 Fold의 정보가 스케일링 통계에 포함되는 미묘한 데이터 누출이 발생합니다.
Chapter 17

비지도 학습 - 군집화 (Clustering)

17.1 비지도 학습이란?

지금까지 배운 알고리즘은 모두 정답(y)이 있는 지도 학습이었습니다. 비지도 학습은 정답 없이 데이터의 구조와 패턴을 스스로 발견합니다. 대표적인 비지도 학습 기법이 군집화(Clustering)입니다.

군집화는 비슷한 데이터끼리 그룹으로 묶는 것입니다. 고객 세분화, 이미지 분할, 이상치 탐지 등에 활용됩니다.

17.2 K-Means 군집화

K-Means는 가장 대표적인 군집화 알고리즘으로, 데이터를 K개의 그룹으로 나눕니다. 각 그룹의 중심(centroid)을 반복적으로 이동시키며 최적의 그룹을 찾습니다.

Python
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import numpy as np

# 인공 데이터 생성 (3개 클러스터)
X, y_true = make_blobs(
    n_samples=300, centers=3,
    cluster_std=1.0, random_state=42
)

# 스케일링
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# K-Means 모델
kmeans = KMeans(
    n_clusters=3,         # 클러스터 수
    init='k-means++',     # 초기 중심 설정 방법
    n_init=10,             # 초기화 반복 횟수
    max_iter=300,          # 최대 반복 횟수
    random_state=42
)
kmeans.fit(X_scaled)

# 결과 확인
print("클러스터 라벨:", np.unique(kmeans.labels_))
print("클러스터별 데이터 수:")
for i in range(3):
    print(f"  클러스터 {i}: {(kmeans.labels_ == i).sum()}개")
print(f"관성(Inertia): {kmeans.inertia_:.2f}")

17.3 최적의 K 찾기 - 엘보우 방법

K를 몇으로 설정해야 할까요? 엘보우(Elbow) 방법은 K를 1부터 늘려가며 관성(Inertia, 클러스터 내 거리 합)을 측정하고, 관성이 급격히 감소하다가 완만해지는 "팔꿈치" 지점을 찾는 방법입니다.

Python
# 엘보우 방법으로 최적 K 탐색
inertias = []
K_range = range(1, 11)

for k in K_range:
    km = KMeans(n_clusters=k, random_state=42, n_init=10)
    km.fit(X_scaled)
    inertias.append(km.inertia_)
    print(f"K={k:2d} → Inertia: {km.inertia_:.2f}")

# 시각화
plt.figure(figsize=(8, 4))
plt.plot(K_range, inertias, 'o-', color='#f57c00')
plt.xlabel('K (클러스터 수)')
plt.ylabel('Inertia')
plt.title('엘보우 방법')
plt.grid(True, alpha=0.3)
plt.show()

17.4 실루엣 점수

실루엣 점수(Silhouette Score)는 군집화 품질을 -1~1 사이의 값으로 평가합니다. 1에 가까울수록 군집이 잘 분리되었다는 의미입니다.

Python
from sklearn.metrics import silhouette_score

for k in range(2, 8):
    km = KMeans(n_clusters=k, random_state=42, n_init=10)
    labels = km.fit_predict(X_scaled)
    sil = silhouette_score(X_scaled, labels)
    print(f"K={k} → 실루엣 점수: {sil:.4f}")
실행 결과
K=2 → 실루엣 점수: 0.5826 K=3 → 실루엣 점수: 0.5666 K=4 → 실루엣 점수: 0.4488 K=5 → 실루엣 점수: 0.3896 K=6 → 실루엣 점수: 0.3571 K=7 → 실루엣 점수: 0.3390
Chapter 18

차원 축소 - PCA

18.1 차원의 저주와 차원 축소

특성(차원)이 너무 많으면 오히려 모델 성능이 떨어지는 현상을 "차원의 저주(Curse of Dimensionality)"라고 합니다. 고차원 공간에서는 데이터 간 거리가 비슷해지고, 학습에 필요한 데이터 양이 기하급수적으로 늘어납니다.

차원 축소(Dimensionality Reduction)는 원래 데이터의 중요한 정보는 유지하면서 특성 수를 줄이는 기법입니다.

18.2 PCA (주성분 분석)

PCA(Principal Component Analysis)는 가장 대표적인 차원 축소 기법입니다. 데이터의 분산(퍼짐 정도)을 가장 잘 설명하는 새로운 축(주성분)을 찾아, 이 축으로 데이터를 투영합니다.

Python
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_breast_cancer
import numpy as np

# 30개 특성을 가진 유방암 데이터
cancer = load_breast_cancer()
X = cancer.data
print(f"원본 특성 수: {X.shape[1]}")   # 30

# PCA 전 반드시 스케일링
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# PCA로 30차원 → 2차원 축소
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
print(f"축소 후 특성 수: {X_pca.shape[1]}")   # 2

# 각 주성분이 설명하는 분산 비율
print(f"\n주성분별 설명 분산 비율:")
for i, ratio in enumerate(pca.explained_variance_ratio_):
    print(f"  PC{i+1}: {ratio:.4f} ({ratio*100:.1f}%)")
print(f"  합계: {pca.explained_variance_ratio_.sum():.4f}")
실행 결과
원본 특성 수: 30 축소 후 특성 수: 2 주성분별 설명 분산 비율: PC1: 0.4427 (44.3%) PC2: 0.1897 (19.0%) 합계: 0.6324

18.3 PCA + 분류 모델

Python
from sklearn.pipeline import make_pipeline
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score

# PCA 적용 전후 성능 비교
# 원본 (30차원)
pipe_full = make_pipeline(
    StandardScaler(),
    RandomForestClassifier(n_estimators=100, random_state=42)
)
score_full = cross_val_score(pipe_full, cancer.data, cancer.target, cv=5)

# PCA 적용 (10차원으로 축소)
pipe_pca = make_pipeline(
    StandardScaler(),
    PCA(n_components=10),
    RandomForestClassifier(n_estimators=100, random_state=42)
)
score_pca = cross_val_score(pipe_pca, cancer.data, cancer.target, cv=5)

print(f"원본 (30차원): {score_full.mean():.4f}")
print(f"PCA  (10차원): {score_pca.mean():.4f}")
PCA 사용 시 주의사항
PCA는 반드시 스케일링 후에 적용해야 합니다. 스케일링 없이 PCA를 적용하면, 값이 큰 특성이 주성분을 지배합니다. 또한 PCA로 변환된 주성분은 원래 특성의 해석이 어려워지므로, 해석 가능성이 중요한 경우에는 신중하게 사용하세요.
Chapter 19

실전 프로젝트 - 캘리포니아 집값 예측

지금까지 배운 모든 내용을 종합하여, 실전 머신러닝 프로젝트를 처음부터 끝까지 진행합니다. 캘리포니아 주의 인구조사 데이터를 기반으로 집값을 예측하는 회귀 문제입니다.

19.1 데이터 로드 및 탐색

Python
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing

# 데이터 로드
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target  # 타겟: 중간 집값 (단위: $100,000)

print("=== 데이터셋 정보 ===")
print(f"크기: {df.shape}")
print(f"\n특성 이름: {housing.feature_names}")
print(f"\n처음 5행:")
print(df.head())
print(f"\n기본 통계:")
print(df.describe().round(2))
print(f"\n결측치:")
print(df.isnull().sum())
실행 결과 (요약)
=== 데이터셋 정보 === 크기: (20640, 9) 특성 이름: ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude'] 결측치: MedInc 0 HouseAge 0 ... 0 MedHouseVal 0 dtype: int64

19.2 데이터 분할 및 전처리

Python
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# X, y 분리
X = df.drop('MedHouseVal', axis=1)
y = df['MedHouseVal']

# 분할
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print(f"학습 세트: {X_train.shape}")
print(f"테스트 세트: {X_test.shape}")

# 스케일링
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

19.3 여러 모델 학습 및 비교

Python
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.svm import SVR
from sklearn.metrics import mean_squared_error, r2_score

models = {
    'Linear Regression'  : LinearRegression(),
    'Ridge (α=1)'        : Ridge(alpha=1.0),
    'Lasso (α=0.01)'     : Lasso(alpha=0.01),
    'Decision Tree'      : DecisionTreeRegressor(max_depth=10, random_state=42),
    'Random Forest'      : RandomForestRegressor(n_estimators=100,
                           max_depth=15, random_state=42, n_jobs=-1),
    'Gradient Boosting'  : GradientBoostingRegressor(n_estimators=200,
                           max_depth=5, learning_rate=0.1, random_state=42),
    'SVR (RBF)'          : SVR(kernel='rbf', C=10),
}

print(f"{'모델':25s} {'RMSE':>8s} {'R²':>8s}")
print("-" * 45)

results = {}
for name, model in models.items():
    model.fit(X_train_s, y_train)
    y_pred = model.predict(X_test_s)
    rmse = np.sqrt(mean_squared_error(y_test, y_pred))
    r2 = r2_score(y_test, y_pred)
    results[name] = {'rmse': rmse, 'r2': r2}
    print(f"{name:25s} {rmse:>8.4f} {r2:>8.4f}")
실행 결과
모델 RMSE R² --------------------------------------------- Linear Regression 0.7456 0.5757 Ridge (α=1) 0.7456 0.5757 Lasso (α=0.01) 0.7459 0.5754 Decision Tree 0.6398 0.6878 Random Forest 0.5081 0.8030 Gradient Boosting 0.4726 0.8296 SVR (RBF) 0.5753 0.7475

19.4 최적 모델 튜닝

Python
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint, uniform

# Gradient Boosting 튜닝
param_dist = {
    'n_estimators': randint(100, 500),
    'max_depth': randint(3, 10),
    'learning_rate': uniform(0.01, 0.19),
    'min_samples_split': randint(2, 20),
    'subsample': uniform(0.7, 0.3),
}

random_search = RandomizedSearchCV(
    GradientBoostingRegressor(random_state=42),
    param_distributions=param_dist,
    n_iter=30,
    cv=5,
    scoring='r2',
    random_state=42,
    n_jobs=-1
)
random_search.fit(X_train_s, y_train)

print(f"최적 파라미터: {random_search.best_params_}")
print(f"최고 CV R²: {random_search.best_score_:.4f}")

# 최종 평가
best_model = random_search.best_estimator_
y_pred_best = best_model.predict(X_test_s)
final_rmse = np.sqrt(mean_squared_error(y_test, y_pred_best))
final_r2 = r2_score(y_test, y_pred_best)
print(f"\n최종 테스트 RMSE: {final_rmse:.4f}")
print(f"최종 테스트 R²  : {final_r2:.4f}")

19.5 특성 중요도 분석

Python
# 최적 모델의 특성 중요도
importances = best_model.feature_importances_
feat_imp = sorted(
    zip(housing.feature_names, importances),
    key=lambda x: x[1],
    reverse=True
)

print("=== 특성 중요도 ===")
for name, imp in feat_imp:
    bar = '█' * int(imp * 50)
    print(f"  {name:12s}: {imp:.4f} {bar}")
실행 결과
=== 특성 중요도 === MedInc : 0.5185 █████████████████████████ AveOccup : 0.1393 ██████ Longitude : 0.0939 ████ Latitude : 0.0905 ████ HouseAge : 0.0549 ██ AveRooms : 0.0412 ██ Population : 0.0356 █ AveBedrms : 0.0261 █

19.6 프로젝트 결론

프로젝트 결과 정리
이번 프로젝트에서 7개 모델을 비교한 결과, Gradient Boosting이 가장 좋은 성능을 보였습니다. 하이퍼파라미터 튜닝을 통해 R² 점수를 약 0.83까지 끌어올렸으며, 중간 소득(MedInc)이 집값 예측에 가장 중요한 특성임을 확인했습니다. 실전에서는 여기에 추가적으로 특성 공학(Feature Engineering), 이상치 처리, 더 고도화된 앙상블 기법(XGBoost, LightGBM) 등을 적용하면 성능을 더 높일 수 있습니다.
Chapter 20

부록 - 치트시트 & 학습 로드맵

20.1 Scikit-Learn 핵심 코드 치트시트

Python Cheat Sheet
# =============================================
# Scikit-Learn 치트시트 - 한눈에 보는 핵심 코드
# =============================================

# ── 1. 데이터 분할 ──
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# ── 2. 전처리 ──
from sklearn.preprocessing import StandardScaler, MinMaxScaler
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)  # 학습: fit + transform
X_test_s  = scaler.transform(X_test)       # 테스트: transform만!

# ── 3. 핵심 3단계 ──
model = SomeAlgorithm(params)  # 생성
model.fit(X_train, y_train)    # 학습
y_pred = model.predict(X_test) # 예측

# ── 4. 분류 알고리즘 ──
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.svm import SVC

# ── 5. 회귀 알고리즘 ──
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.svm import SVR

# ── 6. 비지도 학습 ──
from sklearn.cluster import KMeans, DBSCAN
from sklearn.decomposition import PCA

# ── 7. 분류 평가 지표 ──
from sklearn.metrics import (
    accuracy_score,          # 정확도
    precision_score,         # 정밀도
    recall_score,            # 재현율
    f1_score,                # F1
    confusion_matrix,        # 혼동 행렬
    classification_report    # 종합 리포트
)

# ── 8. 회귀 평가 지표 ──
from sklearn.metrics import (
    mean_squared_error,      # MSE
    mean_absolute_error,     # MAE
    r2_score                 # R² Score
)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))

# ── 9. 교차 검증 ──
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')

# ── 10. 하이퍼파라미터 튜닝 ──
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
grid.fit(X_train, y_train)
grid.best_params_       # 최적 파라미터
grid.best_score_        # 최고 교차검증 점수
grid.best_estimator_    # 최적 모델 객체

# ── 11. 파이프라인 ──
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(StandardScaler(), RandomForestClassifier())
pipe.fit(X_train, y_train)
pipe.score(X_test, y_test)

# ── 12. 모델 저장/불러오기 ──
import joblib
joblib.dump(model, 'model.pkl')              # 저장
loaded_model = joblib.load('model.pkl')      # 불러오기

20.2 알고리즘 선택 가이드

상황추천 알고리즘이유
빠른 베이스라인 (분류)LogisticRegression빠르고 해석 가능
빠른 베이스라인 (회귀)LinearRegression, Ridge빠르고 해석 가능
정형 데이터 최고 성능GradientBoosting, XGBoost, LightGBM대부분의 대회에서 우승
해석 가능성 중요DecisionTree, LogisticRegression결과를 설명하기 쉬움
데이터가 적음 (<1000)SVM, KNN소량 데이터에서도 잘 작동
특성이 매우 많음Lasso, PCA + 모델자동 특성 선택/축소
고객 세분화KMeans, DBSCAN비지도 군집화
이미지/텍스트/음성딥러닝 (PyTorch, TF)비정형 데이터에 강함

20.3 자주 하는 실수 & 해결법

실수결과해결법
테스트 데이터에 fit_transform()데이터 누출 (성능 과대평가)테스트는 반드시 transform()만
스케일링 없이 KNN/SVM 사용성능 저하StandardScaler 적용
stratify 미사용 (불균형 데이터)편향된 분할stratify=y 지정
과적합 무시테스트 성능 급락교차 검증, 규제(Ridge/Lasso), max_depth 제한
정확도만 보기불균형 데이터에서 착각Precision, Recall, F1, 혼동행렬 확인
결측치 무시에러 또는 잘못된 학습SimpleImputer로 처리
범주형 변수 미변환에러OneHotEncoder 또는 get_dummies()
random_state 미지정재현 불가능한 결과항상 random_state 설정
전체 데이터로 스케일링 후 분할미묘한 데이터 누출파이프라인 사용

20.4 학습 로드맵

단계기간학습 내용이 튜토리얼
Level 1 입문1~2주머신러닝 개념, 데이터 준비, fit/predict 패턴Ch.1 ~ Ch.6
Level 2 기초2~4주회귀, 분류 알고리즘, 평가 지표Ch.7 ~ Ch.13
Level 3 중급1~2개월교차 검증, 튜닝, 파이프라인, 비지도 학습Ch.14 ~ Ch.18
Level 4 실전2~3개월실전 프로젝트, Kaggle 대회 참가Ch.19 ~ Ch.20
Level 5 고급지속XGBoost/LightGBM, 특성 공학, 딥러닝(PyTorch)추가 학습

20.5 마치며

축하합니다! 전 20장의 Scikit-Learn 완전정복 튜토리얼을 모두 마치셨습니다.

Scikit-Learn은 머신러닝의 기본기를 다지기에 최적의 라이브러리입니다. 일관된 API 패턴 덕분에 하나의 알고리즘을 마스터하면 나머지를 배우는 속도가 비약적으로 빨라집니다. 이 튜토리얼의 예제를 직접 실행하고 변형해 보면서 반복 학습하세요.

Scikit-Learn 학습의 핵심 3원칙

1. 데이터를 이해하세요 — 아무리 좋은 알고리즘도 쓰레기 데이터에서는 쓰레기 결과를 냅니다. 전처리와 탐색적 분석에 전체 시간의 60~80%를 투자하세요.

2. 단순한 모델부터 시작하세요 — 항상 선형 회귀/로지스틱 회귀로 베이스라인을 잡고, 점진적으로 복잡한 모델을 시도하세요. 단순한 모델이 충분히 좋을 때가 많습니다.

3. 과적합을 경계하세요 — 훈련 정확도 99%가 아니라 테스트 정확도가 중요합니다. 교차 검증을 습관화하고, 훈련 점수와 테스트 점수의 차이를 항상 확인하세요.

데이터 과학의 세계에 오신 것을 환영합니다. 이 튜토리얼이 여러분의 머신러닝 여정에 든든한 첫걸음이 되기를 바랍니다!